from demjson import encode
from simplejson import loads as decode
import json
import math
from PIL import Image,ImageDraw
import matplotlib.pyplot as plt
import cv2 as cv2
import numpy as np
from datetime import datetime
import gps_data_source
import argparse 

def getdistance(lonA,latA,lonB,latB):
    earthR = 6371000
    lat1_rad = math.radians(latA)
    lon1_rad = math.radians(lonA)
    lat2_rad = math.radians(latB)
    lon2_rad = math.radians(lonB)

    difflon = lon2_rad - lon1_rad
    difflat = lat2_rad - lat1_rad
    a = math.sin(difflat / 2) * math.sin(difflat / 2) + math.cos(latA) * math.cos(latB) * math.sin(difflon / 2) * math.sin(difflon / 2)
    a = abs(a)
    c = 2 * math.asin(math.sqrt(a))
    distance = c * earthR
    return distance


class ptMap():
    def __init__(self,sizex=1000,sizey=1000):               
        self.minxindex = 0
        self.minxvalue = 0
        self.minyindex = 0
        self.minyvalue = 0
        self.maxxindex = 0
        self.maxxvalue = 0
        self.maxyindex = 0
        self.maxyvalue = 0
        self._tracklist = []
        self._trackdict = {}
        self.contours = []
        self.sizex = sizex
        self.sizey = sizey 
        self.arearate = 1
        self.baserate = 1
        self.pixdistance = 0

    def getMinDataFull(self,index):
        minindex = 0
        for i,value in enumerate(self._tracklist):
            if value[index]<self._tracklist[minindex][index]:
                minindex = i
        return minindex,self._tracklist[minindex][index]

    def getMaxDataFull(self,index):
        maxindex = 0
        for i,value in enumerate(self._tracklist):
            if value[index]>=self._tracklist[maxindex][index]:
                maxindex = i
        return maxindex,self._tracklist[maxindex][index]

    def pushtracklist(self,tracklist):
        self._tracklist = tracklist
        self.contours.clear()
        self.minxindex,self.minxvalue = self.getMinDataFull(0)
        self.minyindex,self.minyvalue = self.getMinDataFull(1)

        self.maxxindex,self.maxxvalue = self.getMaxDataFull(0)
        self.maxyindex,self.maxyvalue = self.getMaxDataFull(1)

        if self.sizex==0:
           self.sizex = (self.maxxvalue - self.minxvalue)/(self.pixdistance*0.000009)
           self.sizey = (self.maxyvalue - self.minyvalue)/(self.pixdistance*0.000009)
        else:
            if self.maxxvalue - self.minxvalue>0:
                baseratex = self.sizex/(self.maxxvalue - self.minxvalue)
            else:
                baseratex = 90000

            if self.maxyvalue - self.minyvalue>0:
                baseratey = self.sizey/(self.maxyvalue - self.minyvalue)
            else:
                baseratey = 90000

            self.baserate = int(min(baseratex,baseratey,90000))
            self.arearate = 1000000/(9*self.baserate)

    def setpixdistance(self,distance):
        self.pixdistance =  distance

    def pushtrackdict(self,trackdict):
        self._trackdict = trackdict
        self._tracklist = list(trackdict.values())
        self.contours.clear()
        self.minxindex,self.minxvalue = self.getMinDataFull(0)
        self.minyindex,self.minyvalue = self.getMinDataFull(1)

        self.maxxindex,self.maxxvalue = self.getMaxDataFull(0)
        self.maxyindex,self.maxyvalue = self.getMaxDataFull(1)
        baseratex = self.sizex/(self.maxxvalue - self.minxvalue)
        baseratey = self.sizey/(self.maxyvalue - self.minyvalue)

        self.baserate = int(min(baseratex,baseratey,50000))

    def getmappos(self,x,y):
        vx0 = (x - self.minxvalue)*self.baserate + 12
        vy0 = (y - self.minyvalue)*self.baserate + 12
        return vx0,vy0
    
    def pushcontour(self,contour):
        self.contours.append(contour)

    def checkpoint(self,lat,lon):
        x,y = self.getmappos(lat,lon)
        for i in range(len(self.contours)):
            result = cv2.pointPolygonTest(self.contours[i], (x, y), False)
            if result>=0:
                return i+1
        return 0
    
    def getCanvassize(self):
        return int(self.sizex+24),int(self.sizey+24)

    def getminarea(self):
        return self.baserate/1000

class TrackRepack():
    def __init__(self) -> None:
        pass

    def parseData(self,context,blurLevel=7,calcWorkStatus=False,showImage=True,outfile='',drawWorkLine=False):

        x = []
        y = []

        jsdata = context

        prelat = 0
        prelng = 0
        distance =  0
        index = 0

        tracklist = []
        isinit = False
        temptrack = []
        time_format = "%Y-%m-%d %H:%M:%S"
        temptime = datetime.strptime('1970-01-01 00:00:00',time_format)

        lat_flag = 'lat'
        lng_flag = 'lon'
        for item in jsdata['data']['trackList']:
            tmpdistance = 0
            if prelat>0:
                tmpdistance =  getdistance(prelat,prelng,float(item[lat_flag]),float(item[lng_flag]))

            newtime = datetime.strptime(item['time'],time_format)
            time_diff = newtime - temptime

            if calcWorkStatus or not ('isWork' in item):
               iswork = tmpdistance<100 and tmpdistance>0  #float(item['speed'])>0.2 and float(item['speed'])<5 #and int(item['isWork'])>0
            else:
               iswork = int(item['isWork'])>0
            
            temptime = newtime
            #iswork =  float(item['speed'])>0.1 and float(item['speed'])<5.0
            #trackdict[item['id']]=(float(item[lat_flag]),float(item[lng_flag]),iswork)

            if iswork:
                if isinit and len(temptrack)>0:
                    tracklist.extend(temptrack)
                    pass
                temptrack.clear()       
                tracklist.append((float(item[lat_flag]),float(item[lng_flag]),iswork,tmpdistance,time_diff.seconds))     
                isinit = True
                distance += tmpdistance
            else:
                temptrack.append((float(item[lat_flag]),float(item[lng_flag]),iswork,tmpdistance,time_diff.seconds))

            prelat = float(item[lat_flag])
            prelng = float(item[lng_flag])    
    
        basedistance = distance
        if len(tracklist)==0:
            return 0,0,0.0,0
        
        if showImage:
            plt.figure(figsize=(16,9))
            v1 = plt.subplot(2,1,1)
        mPtMap = ptMap(2000,2000)
        mPtMap.setpixdistance(1)
        mPtMap.pushtracklist(tracklist)

        winx,winy = mPtMap.getCanvassize()
        mymap = Image.new('RGB',(winx,winy),(0,0,0))
        mycanvs = ImageDraw.Draw(mymap)


        #画原始图
        for i in range(len(tracklist)):
            if i>0:
                vx0,vy0 = mPtMap.getmappos(tracklist[i-1][0],tracklist[i-1][1])
                vx1,vy1 = mPtMap.getmappos(tracklist[i][0],tracklist[i][1])
                width=1
                if tracklist[i-1][2] and tracklist[i][2]:
                    width = 2
                mycanvs.line((vx0,vy0,vx1,vy1),fill='white',width=width)

            if  not calcWorkStatus:    
                vx1,vy1 = mPtMap.getmappos(tracklist[i][0],tracklist[i][1])
                if tracklist[i][2]:
                    mycanvs.ellipse((vx1-2,vy1-2,vx1 + 2,vy1 + 2),fill='white')
                else:
                    mycanvs.ellipse((vx1,vy1,vx1+ 1,vy1+ 1),fill='gray')
                
        baseimg = cv2.cvtColor(np.array(mymap), cv2.COLOR_RGB2BGR)
        gray = cv2.cvtColor(baseimg, cv2.COLOR_BGR2GRAY)
        img = cv2.medianBlur(gray,blurLevel)


        _, thresh = cv2.threshold(img,100,250,cv2.THRESH_BINARY )
        contours,_ = cv2.findContours(thresh,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE )
        contourindex = 0
        totalarea = 0
        for contour in contours:
            area = cv2.contourArea(contour)
            if area>mPtMap.getminarea() and contour[0][0][0]>0:       
                contourindex += 1
                totalarea += area/667
                mPtMap.pushcontour(contour)

        #二次计算
        tmpdistance = 0
        distance = 0
        prelat = 0
        prelng = 0

        for i in range(len(jsdata['data']['trackList'])):
            tmpdistance = 0
            x = float(jsdata['data']['trackList'][i]['lat'])
            y = float(jsdata['data']['trackList'][i]['lon'])
            icnt = mPtMap.checkpoint(x,y)
            if icnt>0:
                if prelat>0:
                    tmpdistance = getdistance(prelat,prelng,x,y)
                prelat = x
                prelng = y  
            else:
               prelat = 0
               prelng = 0            
            distance += tmpdistance  
        
        mymap.close()
        
        return basedistance,distance,distance*1.30/667,contourindex

    def parsefile(self,filename,blurLevel=7,calcWorkStatus=False,showImage=True,outfile='',drawWorkLine=False):
        with open(filename) as f:
            txt = f.read()
        jsdata = decode(txt)
        self.parseData(jsdata,blurLevel,calcWorkStatus,showImage,outfile,drawWorkLine)


    def paraseSql(self,datasource, date="",dtu="",blurLevel=7,calcWorkStatus=False,showImage=True,outfile='',drawWorkLine=False):
        icount = 0
        if dtu=="":
            idlist = datasource.getidlist(date)
            totalcount = len(idlist)
            ipos = 0
            for dtuitem in idlist:                
                jsdata = datasource.getdata(dtuitem,date)
                d1,d2,area,block = self.parseData(jsdata,blurLevel,calcWorkStatus,showImage,outfile,drawWorkLine)
                datasource.writedata(date,dtuitem,area,block,d1,d2)
                ipos+=1
                progess = int(ipos*100.0/totalcount)
                flag =">"*progess
                print("\r{0} {1:.1f}%".format(flag,ipos*100.0/totalcount), end="")
        else:
            jsdata = datasource.getdata(dtu,date)
            d1,d2,area,block = self.parseData(jsdata,blurLevel,calcWorkStatus,showImage,outfile,drawWorkLine)
            datasource.writedata(date,dtu,area,block,d1,d2)

        datasource.commit()
        print("\nfinish")
        
parser = argparse.ArgumentParser(description='Demo of argparse')
parser.add_argument('--d', type=str, default="",help="日期")
parser.add_argument('--c', type=str, default="",help="设备号")
parser.add_argument('--l', type=int, default=7,help="级别")

args = parser.parse_args()

if len(args.d)!=8:
    print("*******日期格式错误*******")    
else:
    mpack = TrackRepack()
    ds = gps_data_source.gps_data()
    record_date = args.d
    dtu_data = args.c
    level = args.l 
    mpack.paraseSql(ds,date=record_date,dtu=dtu_data,blurLevel=level,calcWorkStatus=True,drawWorkLine=False,showImage=False)